using System.Security.Cryptography;
using System.Text;

namespace oms.Shared.utils;

/// <summary>
/// 密码加密工具类（使用加盐MD5算法）
/// </summary>
public static class PasswordUtil
{
    /// <summary>
    /// 密码加密（自动生成盐值）
    /// </summary>
    /// <param name="plaintext">密码明文</param>
    /// <returns>加密串（格式：16位盐值 + 加密结果）</returns>
    /// <exception cref="ArgumentException">明文为空时抛出</exception>
    public static string Encode(string plaintext)
    {
        if (string.IsNullOrEmpty(plaintext))
            throw new ArgumentException("原文不能为空。", nameof(plaintext));

        // 生成8字节随机盐值（转为16位十六进制字符串）
        var saltBytes = new byte[8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(saltBytes);
        }

        var salt = Convert.ToHexStringLower(saltBytes);

        return Encode(plaintext, salt);
    }

    /// <summary>
    /// 使用指定盐值加密密码
    /// </summary>
    /// <param name="plaintext">密码明文</param>
    /// <param name="salt">盐值（16位十六进制字符串）</param>
    /// <returns>加密串（格式：16位盐值 + 加密结果）</returns>
    private static string Encode(string plaintext, string salt)
    {
        if (string.IsNullOrEmpty(salt))
            throw new ArgumentException("盐值不能为空。", nameof(salt));
        if (string.IsNullOrEmpty(plaintext))
            throw new ArgumentException("原文不能为空。", nameof(plaintext));

        var saltBytes = Encoding.UTF8.GetBytes(salt);
        var digest = MD5.HashData(Encoding.UTF8.GetBytes(plaintext));

        var totalLength = 5 * (saltBytes.Length + digest.Length);
        var allData = new byte[totalLength];
        var offset = 0;
        
        for (var i = 0; i < 5; i++)
        {
            // 复制盐值到总数据
            Buffer.BlockCopy(saltBytes, 0, allData, offset, saltBytes.Length);
            offset += saltBytes.Length;

            // 复制当前digest到总数据
            Buffer.BlockCopy(digest, 0, allData, offset, digest.Length);
            offset += digest.Length;
            
        }
        
        var finalDigest = MD5.HashData(allData);
        
        var encodeStr = Convert.ToHexStringLower(finalDigest);
        
        return salt + encodeStr;
    }

    /// <summary>
    /// 验证密码明文是否匹配加密串
    /// </summary>
    /// <param name="plaintext">密码明文</param>
    /// <param name="ciphertext">加密串（格式：16位盐值 + 加密结果）</param>
    /// <returns>是否匹配</returns>
    /// <exception cref="ArgumentException">加密串格式不正确时抛出</exception>
    public static bool Matches(string plaintext, string ciphertext)
    {
        if (string.IsNullOrEmpty(ciphertext) || ciphertext.Length < 16)
            throw new ArgumentException("加密串格式不正确。", nameof(ciphertext));

        // 提取前16位作为盐值（与Java的substring(0, 16)一致）
        var salt = ciphertext[..16];
        // 使用相同盐值加密明文，对比结果
        var encrypted = Encode(plaintext, salt);
        return encrypted == ciphertext;
    }
}